package com.lightproxy.test.demo;

import io.netty.handler.codec.http.HttpRequest;
import org.littleshoot.proxy.mitm.Authority;
import org.littleshoot.proxy.mitm.BouncyCastleSslEngineSource;
import org.littleshoot.proxy.mitm.CertificateSniffingMitmManager;
import org.littleshoot.proxy.mitm.FakeCertificateException;
import org.littleshoot.proxy.mitm.RootCertificateException;
import org.littleshoot.proxy.mitm.SubjectAlternativeNameHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;

public class MyMitmManager extends CertificateSniffingMitmManager {

    private static final Logger LOG = LoggerFactory.getLogger(MyMitmManager.class);

    private List<Object> subjectAlternativeNames;

    private BouncyCastleSslEngineSource sslEngineSource;

    public MyMitmManager() throws RootCertificateException {
    }

    public MyMitmManager(Authority authority) throws RootCertificateException {
        super(authority);
    }

    public MyMitmManager(Authority authority,List<Object> subjectAlternativeNames) throws RootCertificateException {
        try {
            this.sslEngineSource = new BouncyCastleSslEngineSource(authority, true, true);
        } catch (Exception var3) {
            throw new RootCertificateException("Errors during assembling root CA.", var3);
        }
        this.subjectAlternativeNames = subjectAlternativeNames;
    }

    public SSLEngine clientSslEngineFor(HttpRequest httpRequest, SSLSession serverSslSession) {
        try {
            X509Certificate upstreamCert = this.getCertificateFromSession(serverSslSession);
            String commonName = this.getCommonName(upstreamCert);
            SubjectAlternativeNameHolder san = new SubjectAlternativeNameHolder();
            san.addAll(upstreamCert.getSubjectAlternativeNames());
            if(subjectAlternativeNames != null){
                san.addAll(Arrays.<List<?>>asList(subjectAlternativeNames));
            }
            LOG.debug("Subject Alternative Names: {}", san);
            return this.sslEngineSource.createCertForHost(commonName, san);
        } catch (Exception var6) {
            throw new FakeCertificateException("Creation dynamic certificate failed", var6);
        }
    }

    private X509Certificate getCertificateFromSession(SSLSession sslSession) throws SSLPeerUnverifiedException {
        Certificate[] peerCerts = sslSession.getPeerCertificates();
        Certificate peerCert = peerCerts[0];
        if (peerCert instanceof X509Certificate) {
            return (X509Certificate)peerCert;
        } else {
            throw new IllegalStateException("Required java.security.cert.X509Certificate, found: " + peerCert);
        }
    }
    private String getCommonName(X509Certificate c) {
        LOG.debug("Subject DN principal name: {}", c.getSubjectDN().getName());
        String[] arr$ = c.getSubjectDN().getName().split(",\\s*");
        int len$ = arr$.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            String each = arr$[i$];
            if (each.startsWith("CN=")) {
                String result = each.substring(3);
                LOG.debug("Common Name: {}", result);
                return result;
            }
        }

        throw new IllegalStateException("Missed CN in Subject DN: " + c.getSubjectDN());
    }


}
